﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading;
using nwrole.plugin;

namespace nwrole.lib {
    public class SupervisorHost {
        
        private Supervisor supervisor;
        private ServiceHost serviceHost;
        // private int supervisorPort;

        private AutoResetEvent waitEvent = new AutoResetEvent(false);

        private bool running;

        private static void WriteLog(string content) {
            try {
                string logDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "log/Supervisor/");
                if (!System.IO.Directory.Exists(logDir))
                    System.IO.Directory.CreateDirectory(logDir);

                DateTime now = DateTime.Now;

                System.IO.File.AppendAllText(logDir + "log " + now.ToString("yyyy-MM-dd") + ".txt", now.ToString("yyyy-MM-dd HH:mm:ss ") + content + "\r\n");
            } catch (Exception) {
            }
        }

        public SupervisorHost(IServiceProvider serviceProvider, string pluginProviderClassName, int supervisorPort) {
            // this.supervisorPort = supervisorPort;
            supervisor = new Supervisor(serviceProvider, pluginProviderClassName, supervisorPort);
        }

        public bool Start()
        {
            new Thread(ThreadStart).Start();

            return true;
        }

        public void Stop()
        {
            WriteLog("SupervisorHost Stop");
            running = false;
            waitEvent.Set();
        }

        private void ThreadStart()
        {
            running = true;
            StartServiceHost();

            while (running)
            {
                waitEvent.WaitOne(5000);
            }

            if (serviceHost != null)
            {
                supervisor.Stop();
                serviceHost.Close();
                serviceHost = null;
                supervisor = null;
            }
        }

        private bool StartServiceHost()
        {
            try
            {
                WriteLog("SupervisorHost Start");

                if (serviceHost != null)
                    serviceHost.Close();
                if (supervisor != null)
                    supervisor.Stop();

                WriteLog("SupervisorHost opening service host");

                Uri baseAddress = new Uri("net.tcp://localhost:" + supervisor.SupervisorPort);

                //this.supervisor = supervisor;
                //supervisor = new Supervisor(serviceProvider, pluginProviderClassName, supervisorPort);
                serviceHost = new ServiceHost(supervisor, baseAddress);
                NetTcpBinding binding = new NetTcpBinding();
                binding.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
                binding.MaxReceivedMessageSize = 2147483647;
                binding.ReceiveTimeout = new TimeSpan(0, 0, 120);
                serviceHost.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
                serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = System.ServiceModel.Security.UserNamePasswordValidationMode.Windows;
                serviceHost.AddServiceEndpoint(typeof(ISupervisorContract), binding, "Supervisor");
                serviceHost.Faulted += new EventHandler(serviceHost_Faulted);
                serviceHost.Opening += new EventHandler(serviceHost_Opening);
                serviceHost.Opened += new EventHandler(serviceHost_Opened);
                serviceHost.Open();

                WriteLog("SupervisorHost Starting supervisor");

                supervisor.Start();

                WriteLog("SupervisorHost Started");
            }
            catch (Exception exception)
            {
                WriteLog("SupervisorHost Start exception: " + exception);
                EventLogger.LogException("SupervisorHost exception: ", exception);
                return false;
            }

            return true;
        }

        public void Test(string msg) {
            supervisor.LogSupervisor(LogLevel.Debug, msg, null);
        }

        private void serviceHost_Opened(object sender, EventArgs e) {
        }

        private void serviceHost_Opening(object sender, EventArgs e) {
        }

        private void serviceHost_Faulted(object sender, EventArgs e) {
            StringBuilder sb = new StringBuilder();
            if (sender != null) {
                sb.Append(sender.ToString());
            }
            if (e != null) {
                sb.Append(e.ToString());
            }

            WriteLog("SupervisorHost faulted: " + sb);
            EventLogger.LogInformation("SupervisorHost faulted: " + sb);

            StartServiceHost();
        }
    }
}
